

#include <ov5640_i2c.h>
#include <ov5640_port.h>
#include <ov5640_bsp_msp.h>

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* I2C handler declaration */
static I2C_HandleTypeDef ov5640_i2c_handle;

/** @defgroup STM32H7B3I_EVAL_BUS_Exported_Functions BUS Exported Functions
 * @{
 */
/**
 * @brief  Initializes I2C HAL.
 * @retval BSP status
 */
int32_t ov5640_i2c_init(void)
{
    int32_t ret = OV5640_I2C_SUCCESS;

    ov5640_i2c_handle.Instance = OV5640_I2C;
    if (HAL_I2C_GetState(&ov5640_i2c_handle) == HAL_I2C_STATE_RESET)
    {
        ov5640_i2c_msp_init(&ov5640_i2c_handle);
    }

    if (ov5640_i2c_mx_init(&ov5640_i2c_handle) != HAL_OK)
    {
        ret = OV5640_I2C_ERROR;
    }

    return ret;
}

/**
 * @brief  DeInitializes I2C HAL.
 * @retval BSP status
 */
int32_t ov5640_i2c_deinit(void)
{
    int32_t ret = OV5640_I2C_SUCCESS;

    ov5640_i2c_msp_deinit(&ov5640_i2c_handle);

    /* Init the I2C */
    if (HAL_I2C_DeInit(&ov5640_i2c_handle) != HAL_OK)
    {
        ret = OV5640_I2C_ERROR;
    }

    return ret;
}

/**
 * @brief  Write a 8bit value in a register of the device through BUS.
 * @param  DevAddr Device address on Bus.
 * @param  Reg    The target register address to write
 * @param  pData  The target register value to be written
 * @param  Length buffer size to be written
 * @retval BSP status
 */
int32_t ov5640_i2c_write_reg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length)
{
    int32_t ret;

    if (HAL_I2C_Mem_Write(&ov5640_i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000) == HAL_OK)
    {
        ret = OV5640_I2C_SUCCESS;
    }
    else
    {
        if (HAL_I2C_GetError(&ov5640_i2c_handle) == HAL_I2C_ERROR_AF)
        {
            // ret = BSP_ERROR_BUS_ACKNOWLEDGE_FAILURE;
            ret = OV5640_I2C_ERROR;
        }
        else
        {
            // ret = BSP_ERROR_PERIPH_FAILURE;
            ret = OV5640_I2C_ERROR;
        }
    }

    return ret;
}

/**
 * @brief  Read a 8bit register of the device through BUS
 * @param  DevAddr Device address on BUS
 * @param  Reg     The target register address to read
 * @param  pData   Pointer to data buffer
 * @param  Length  Length of the data
 * @retval BSP status
 */
int32_t ov5640_i2c_read_reg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length)
{
    int32_t ret;

#if defined(BSP_USE_CMSIS_OS)
    /* Get semaphore to prevent multiple I2C access */
    osSemaphoreWait(BspI2cSemaphore, osWaitForever);
#endif

    if (HAL_I2C_Mem_Read(&ov5640_i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000) == HAL_OK)
    {
        ret = OV5640_I2C_SUCCESS;
    }
    else
    {
        if (HAL_I2C_GetError(&ov5640_i2c_handle) == HAL_I2C_ERROR_AF)
        {
            // ret = BSP_ERROR_BUS_ACKNOWLEDGE_FAILURE;
            ret = OV5640_I2C_ERROR;
        }
        else
        {
            // ret = BSP_ERROR_PERIPH_FAILURE;
            ret = OV5640_I2C_ERROR;
        }
    }

#if defined(BSP_USE_CMSIS_OS)
    /* Release semaphore to prevent multiple I2C access */
    osSemaphoreRelease(BspI2cSemaphore);
#endif
    return ret;
}

/**
 * @brief  Write a 16bit value in a register of the device through BUS.
 * @param  DevAddr Device address on Bus.
 * @param  Reg    The target register address to write
 * @param  pData  The target register value to be written
 * @param  Length buffer size to be written
 * @retval BSP status
 */
int32_t ov5640_i2c_write_reg_16bit(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length)
{
    int32_t ret;

#if defined(BSP_USE_CMSIS_OS)
    /* Get semaphore to prevent multiple I2C access */
    osSemaphoreWait(BspI2cSemaphore, osWaitForever);
#endif

    if (HAL_I2C_Mem_Write(&ov5640_i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_16BIT, pData, Length, 10000) == HAL_OK)
    {
        ret = OV5640_I2C_SUCCESS;
    }
    else
    {
        if (HAL_I2C_GetError(&ov5640_i2c_handle) == HAL_I2C_ERROR_AF)
        {
            // ret = BSP_ERROR_BUS_ACKNOWLEDGE_FAILURE;
            ret = OV5640_I2C_ERROR;
        }
        else
        {
            // ret = BSP_ERROR_PERIPH_FAILURE;
            ret = OV5640_I2C_ERROR;
        }
    }

#if defined(BSP_USE_CMSIS_OS)
    /* Release semaphore to prevent multiple I2C access */
    osSemaphoreRelease(BspI2cSemaphore);
#endif
    return ret;
}

/**
 * @brief  Read a 16bit register of the device through BUS
 * @param  DevAddr Device address on BUS
 * @param  Reg     The target register address to read
 * @param  pData   Pointer to data buffer
 * @param  Length  Length of the data
 * @retval BSP status
 */
int32_t ov5640_i2c_read_reg_16bit(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length)
{
    int32_t ret;

#if defined(BSP_USE_CMSIS_OS)
    /* Get semaphore to prevent multiple I2C access */
    osSemaphoreWait(BspI2cSemaphore, osWaitForever);
#endif

    if (HAL_I2C_Mem_Read(&ov5640_i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_16BIT, pData, Length, 10000) == HAL_OK)
    {
        ret = OV5640_I2C_SUCCESS;
    }
    else
    {
        if (HAL_I2C_GetError(&ov5640_i2c_handle) == HAL_I2C_ERROR_AF)
        {
            // ret = BSP_ERROR_BUS_ACKNOWLEDGE_FAILURE;
            ret = OV5640_I2C_ERROR;
        }
        else
        {
            // ret = BSP_ERROR_PERIPH_FAILURE;
            ret = OV5640_I2C_ERROR;
        }
    }

#if defined(BSP_USE_CMSIS_OS)
    /* Release semaphore to prevent multiple I2C access */
    osSemaphoreRelease(BspI2cSemaphore);
#endif
    return ret;
}

int32_t ov5640_i2c_rx(uint16_t DevAddr, uint16_t Reg, uint16_t MemAddSize, uint8_t *pData, uint16_t Length)
{
    return 0;
}

int32_t ov5640_i2c_tx(uint16_t DevAddr, uint16_t Reg, uint16_t MemAddSize, uint8_t *pData, uint16_t Length)
{
    return 0;
}

/**
 * @brief  Checks if target device is ready for communication.
 * @note   This function is used with Memory devices
 * @param  DevAddr  Target device address
 * @param  Trials      Number of trials
 * @retval BSP status
 */
int32_t ov5640_i2c_is_ready(uint16_t DevAddr, uint32_t Trials)
{
    int32_t ret = OV5640_I2C_SUCCESS;

#if defined(BSP_USE_CMSIS_OS)
    /* Get semaphore to prevent multiple I2C access */
    osSemaphoreWait(BspI2cSemaphore, osWaitForever);
#endif

    if (HAL_I2C_IsDeviceReady(&ov5640_i2c_handle, DevAddr, Trials, 1000) != HAL_OK)
    {
        // ret = BSP_ERROR_BUSY;
        ret = OV5640_I2C_ERROR;
    }

#if defined(BSP_USE_CMSIS_OS)
    /* Release semaphore to prevent multiple I2C access */
    osSemaphoreRelease(BspI2cSemaphore);
#endif

    return ret;
}

/**
 * @brief  Delay function
 * @retval Tick value
 */
int32_t ov5640_get_tick(void)
{
    return (int32_t)HAL_GetTick();
}

void I2Cx_EV_IRQHandler(void)
{
    HAL_I2C_EV_IRQHandler(&ov5640_i2c_handle);
}

/**
 * @brief  This function handles I2C error interrupt request.
 * @param  None
 * @retval None
 * @Note   This function is redefined in "main.h" and related to I2C error
 */
void I2Cx_ER_IRQHandler(void)
{
    HAL_I2C_ER_IRQHandler(&ov5640_i2c_handle);
}

void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *ov5640_i2c_handle)
{
}

void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *ov5640_i2c_handle)
{
}

/**
 * @brief  Rx Transfer completed callback.
 * @param  ov5640_i2c_handle: I2C handle
 * @note   This example shows a simple way to report end of IT Rx transfer, and
 *         you can add your own implementation.
 * @retval None
 */
void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *ov5640_i2c_handle)
{
}

void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *ov5640_i2c_handle)
{
}

/**
 * @brief  I2C error callbacks.
 * @param  ov5640_i2c_handle: I2C handle
 * @note   This example shows a simple way to report transfer error, and you can
 *         add your own implementation.
 * @retval None
 */
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *ov5640_i2c_handle)
{
    if (HAL_I2C_GetError(ov5640_i2c_handle) != HAL_I2C_ERROR_AF)
    {
    }
}